package server.console;

import java.util.ArrayList;

/**
 * Esta clase representa un comando que puede ser ejecutado. Este comando por si mismo no tiene
 * interpretación. Esta interpretacion se la da el objeto que  implemente la interfaz Interprete
 * @see Interprete
 * @author romeroy
 *
 */
public class Orden {
	/**
	 * Nombre del comando
	 */
	private String nombre;
	
	/**
	 * Argumentos que recibe el comando. Queda en el interprete saber que significan
	 */
	private ArrayList<String> argumentos;

	/**
	 * Construye un comando vacio
	 */
	public Orden() {
		this.argumentos= new ArrayList<String>();
	}

	/**
	 * Construye el comando a partir de una sentencia. A partir de la sentencia identifica
	 * el nombre y los arguementos del comando
	 * @param sentencia
	 */
	public Orden(String sentencia) {
		this();
		parseArguments(sentencia);
	}

	/**
	 * Obtiene el nombre del comando
	 * @return nombre del comando
	 */
	public String getNombre() {
		return nombre;
	}

	/**
	 * Establece el nombre del comando
	 * @param nombre Nombre del comando
	 */
	public void setNombre(String nombre) {
		this.nombre = nombre;
	}
	
	/**
	 * Obtiene los argumentos del comando
	 * @return
	 */
	public ArrayList<String> getArgumentos() {
		return argumentos;
	}

	/**
	 * Establece los argumentos
	 * @param argumentos
	 */
	public void setArgumentos(ArrayList<String> argumentos) {
		this.argumentos = argumentos;
	}
	

	/**
	 * Genera una lista de Strings que representan a los argumentos del comando
	 * @param sentencia
	 */
	private void parseArguments(String sentencia) {
		//XXX Expresiones regulares?
		if(sentencia.contains(" ") && (sentencia.contains("\"") || sentencia.contains("'"))) {
			parseArgumentsConEspacio(sentencia);
			return;
		}
		
		String s[] = sentencia.split(" ");
		int cantidad = s.length;
		this.nombre = s[0];

		if (cantidad > 1) {
			for (int i = 1; i < cantidad; i++)
				this.argumentos.add(s[i]);
		}
	}

	/**
	 * Genera una lista de Strings que representan a los argumentos del comando. En este caso los argumentos
	 * pueden contener espacios y estar contenidos entre comillas dobles o simples
	 * @param sentencia
	 */
	private void parseArgumentsConEspacio(String sentencia) {
		StringBuilder sb = new StringBuilder();
		boolean comillas = false;
		int length = sentencia.length();
		// Busco el primer espacio que delimitara el nombre del comando
		int i = sentencia.indexOf(" ");
		this.nombre = sentencia.substring(0, i++);
		// Recorro lo que queda de la sentencia en busca de los argumentos
		char c;
		while (i < length) {
			c = sentencia.charAt(i);
			// busco comillas, son las que pueden contener argumentos con espacios
			if (c == '"' || c == '\'') {
				comillas = !comillas;
			// Si encuentro un espacio y no tengo ninguna comilla pendiente a cerrar, agrego el argumento a la lista
			} else if (c == ' ' && !comillas) {
				this.argumentos.add(sb.toString());
				sb = new StringBuilder();
				comillas = false;
			} else {
			// Sino agrego el caracter al argumento actual
				sb.append(c);
			}
			i++;
		}
		// Agrego el ultimo argumento que no agregue antes
		this.argumentos.add(sb.toString());
	}

	@Override
	public String toString() {
		StringBuilder sb = new StringBuilder();
		sb.append(this.nombre);
		if (this.argumentos != null) {
			for (String argumento : this.argumentos)
				sb.append(" " + argumento);
		}
		return sb.toString();
	}
}
